{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 170,
   "id": "a1aa1b43-7a47-4aca-ae5f-94a9d4ba2d89",
   "metadata": {},
   "outputs": [],
   "source": [
    "## Clinic Booking Bot\n",
    "\n",
    "##Easily book your clinic visit – available only on weekdays between **14:00 and 15:00**.  \n",
    "##Speak or type, and get instant confirmation.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 171,
   "id": "fe798c6a-f8da-46aa-8c0e-9d2623def3d2",
   "metadata": {},
   "outputs": [],
   "source": [
    "# import library\n",
    "\n",
    "import os\n",
    "import json\n",
    "from dotenv import load_dotenv\n",
    "from openai import OpenAI\n",
    "import gradio as gr\n",
    "import base64\n",
    "from io import BytesIO\n",
    "from datetime import date\n",
    "from PIL import Image, ImageDraw, ImageFont\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 172,
   "id": "0ad4e526-e95d-4e70-9faa-b4236b105dd5",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "OpenAI API Key exists and begins sk-proj-\n"
     ]
    }
   ],
   "source": [
    "# Save keys\n",
    "\n",
    "load_dotenv(override=True)\n",
    "\n",
    "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
    "if openai_api_key:\n",
    "    print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
    "else:\n",
    "    print(\"OpenAI API Key not set\")\n",
    "    \n",
    "MODEL = \"gpt-4o-mini\"\n",
    "openai = OpenAI()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 173,
   "id": "ae95308e-0002-4017-9f2c-fcb1ddb248fa",
   "metadata": {},
   "outputs": [],
   "source": [
    "# --- CONFIG ---\n",
    "BOOKING_START = 14\n",
    "BOOKING_END = 15\n",
    "WEEKDAYS = [\"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\"]\n",
    "PHONE = \"010-1234567\"\n",
    "confirmed_bookings = []\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 174,
   "id": "e21b0fd0-4cda-4938-8867-dc2c6e7af4b1",
   "metadata": {},
   "outputs": [],
   "source": [
    "# --- TTS ---\n",
    "def generate_tts(text, voice=\"fable\", filename=\"output.mp3\"):\n",
    "    response = openai.audio.speech.create(\n",
    "        model=\"tts-1\",\n",
    "        voice=\"fable\",\n",
    "        input=text\n",
    "    )\n",
    "    with open(filename, \"wb\") as f:\n",
    "        f.write(response.content)\n",
    "    return filename"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 175,
   "id": "e28a5c3b-bd01-4845-a41e-87823f6bb078",
   "metadata": {},
   "outputs": [],
   "source": [
    "# --- Translate Booking Confirmation ---\n",
    "def translate_text(text, target_language=\"nl\"):\n",
    "    prompt = f\"Translate this message to {target_language}:\\n{text}\"\n",
    "    response = openai.chat.completions.create(\n",
    "        model=\"gpt-4\",\n",
    "        messages=[\n",
    "            {\"role\": \"system\", \"content\": \"You are a helpful translator.\"},\n",
    "            {\"role\": \"user\", \"content\": prompt}\n",
    "        ]\n",
    "    )\n",
    "    return response.choices[0].message.content.strip()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 176,
   "id": "8ed57cc9-7d54-4a5d-831b-0efcc5b7a7a9",
   "metadata": {},
   "outputs": [],
   "source": [
    "# --- Booking Logic ---\n",
    "def book_appointment(name, time_str):\n",
    "    try:\n",
    "        booking_time = datetime.strptime(time_str, \"%H:%M\")\n",
    "    except ValueError:\n",
    "        return \"Invalid time format. Use HH:MM.\", None, None\n",
    "\n",
    "    hour = booking_time.hour\n",
    "    weekday = datetime.today().strftime(\"%A\")\n",
    "\n",
    "    if weekday not in WEEKDAYS:\n",
    "        response = \"Bookings are only available on weekdays.\"\n",
    "    elif BOOKING_START <= hour < BOOKING_END:\n",
    "        confirmation = f\"Booking confirmed for {name} at {time_str}.\"\n",
    "        confirmed_bookings.append((name, time_str))\n",
    "        translated = translate_text(confirmation)\n",
    "        audio = generate_tts(translated)\n",
    "        image = generate_booking_image(name, time_str)\n",
    "        return translated, audio, image\n",
    "    else:\n",
    "        response = \"Sorry, bookings are only accepted between 14:00 and 15:00 on weekdays.\"\n",
    "        translated = translate_text(response)\n",
    "        audio = generate_tts(translated)\n",
    "        return translated, audio, None"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 177,
   "id": "19b52115-f0f3-4d63-a463-886163d4cfd1",
   "metadata": {},
   "outputs": [],
   "source": [
    "# --- Booking Card ---\n",
    "def generate_booking_image(name, time_str):\n",
    "    img = Image.new(\"RGB\", (500, 250), color=\"white\")\n",
    "    draw = ImageDraw.Draw(img)\n",
    "    msg = f\"\\u2705 Booking Confirmed\\nName: {name}\\nTime: {time_str}\"\n",
    "    draw.text((50, 100), msg, fill=\"black\")\n",
    "    return img"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 178,
   "id": "2c446b6c-d410-4ba1-b0c7-c475e5259ff5",
   "metadata": {},
   "outputs": [],
   "source": [
    "# --- Voice Booking ---\n",
    "def voice_booking(audio_path, name):\n",
    "    with open(audio_path, \"rb\") as f:\n",
    "        response = openai.audio.transcriptions.create(model=\"whisper-1\", file=f)\n",
    "    transcription = response.text.strip()\n",
    "\n",
    "    system_prompt = \"\"\"\n",
    "    You are a clinic assistant. Extract only the appointment time from the user's sentence in 24-hour HH:MM format.\n",
    "    If no time is mentioned, respond with 'No valid time found.'\n",
    "    \"\"\"\n",
    "\n",
    "    response = openai.chat.completions.create(\n",
    "        model=\"gpt-4\",\n",
    "        messages=[\n",
    "            {\"role\": \"system\", \"content\": system_prompt},\n",
    "            {\"role\": \"user\", \"content\": transcription}\n",
    "        ]\n",
    "    )\n",
    "    extracted_time = response.choices[0].message.content.strip()\n",
    "\n",
    "    if \":\" in extracted_time:\n",
    "        return book_appointment(name, extracted_time)\n",
    "    else:\n",
    "        message = \"Sorry, I couldn't understand the time. Please try again.\"\n",
    "        translated = translate_text(message)\n",
    "        audio_path = generate_tts(translated)\n",
    "        return translated, audio_path, None"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 179,
   "id": "121d2907-7fa8-4248-b2e7-83617ea66ff0",
   "metadata": {},
   "outputs": [],
   "source": [
    "# --- Chat Bot Handler ---\n",
    "def chat_bot(messages):\n",
    "    system_prompt = \"\"\"\n",
    "    You are a clinic booking assistant. Your job is to:\n",
    "    - Greet the patient and explain your role\n",
    "    - Only assist with making appointments\n",
    "    - Accept bookings only on weekdays between 14:00 and 15:00\n",
    "    - Do not provide medical advice\n",
    "    - Always respond with empathy and clarity\n",
    "    \"\"\"\n",
    "    response = openai.chat.completions.create(\n",
    "        model=\"gpt-4\",\n",
    "        messages=[{\"role\": \"system\", \"content\": system_prompt}] + messages\n",
    "    )\n",
    "    reply = response.choices[0].message.content.strip()\n",
    "    audio = generate_tts(reply)\n",
    "    return reply, audio"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 180,
   "id": "2427b694-8c57-40cb-b202-4a8989547925",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "* Running on local URL:  http://127.0.0.1:7898\n",
      "* To create a public link, set `share=True` in `launch()`.\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div><iframe src=\"http://127.0.0.1:7898/\" width=\"100%\" height=\"500\" allow=\"autoplay; camera; microphone; clipboard-read; clipboard-write;\" frameborder=\"0\" allowfullscreen></iframe></div>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Gradio interface\n",
    "with gr.Blocks(theme=gr.themes.Soft()) as demo:\n",
    "    gr.Markdown(\"\"\"## 🩺 GP Booking Assistant  \n",
    "Only available weekdays between **14:00 and 15:00**  \n",
    "☎️ Contact: {PHONE}\n",
    "---\"\"\")\n",
    "\n",
    "    name_global = gr.Textbox(label=\"Your Name\", placeholder=\"Enter your name\", interactive=True)\n",
    "\n",
    "    with gr.Tab(\"💬 Chat Mode\"):\n",
    "        chatbot = gr.Chatbot(label=\"Booking Chat\", type=\"messages\", height=400)\n",
    "        text_input = gr.Textbox(label=\"Type your message or use your voice below\")\n",
    "        audio_input = gr.Audio(type=\"filepath\", label=\"🎙️ Or speak your request\")\n",
    "        chat_audio_output = gr.Audio(label=\"🔊 Assistant's Reply\", type=\"filepath\")\n",
    "        send_btn = gr.Button(\"Send\")\n",
    "\n",
    "        def handle_chat(user_message, chat_history):\n",
    "            chat_history = chat_history or []\n",
    "            chat_history.append({\"role\": \"user\", \"content\": user_message})\n",
    "            reply, audio = chat_bot(chat_history)\n",
    "            chat_history.append({\"role\": \"assistant\", \"content\": reply})\n",
    "            return chat_history, \"\", audio\n",
    "\n",
    "        def handle_audio_chat(audio_path, chat_history):\n",
    "            with open(audio_path, \"rb\") as f:\n",
    "                transcription = openai.audio.transcriptions.create(model=\"whisper-1\", file=f).text.strip()\n",
    "            return handle_chat(transcription, chat_history)\n",
    "\n",
    "        send_btn.click(handle_chat, [text_input, chatbot], [chatbot, text_input, chat_audio_output])\n",
    "        text_input.submit(handle_chat, [text_input, chatbot], [chatbot, text_input, chat_audio_output])\n",
    "        audio_input.change(handle_audio_chat, [audio_input, chatbot], [chatbot, text_input, chat_audio_output])\n",
    "\n",
    "\n",
    "    \n",
    "    with gr.Tab(\"📝 Text Booking\"):\n",
    "        time_text = gr.Textbox(label=\"Preferred Time (HH:MM)\", placeholder=\"e.g., 14:30\")\n",
    "        btn_text = gr.Button(\"📅 Book via Text\")\n",
    "\n",
    "    with gr.Tab(\"🎙️ Voice Booking\"):\n",
    "        voice_input = gr.Audio(type=\"filepath\", label=\"Say your preferred time\")\n",
    "        btn_voice = gr.Button(\"📅 Book via Voice\")\n",
    "\n",
    "    output_text = gr.Textbox(label=\"Response\", interactive=False)\n",
    "    output_audio = gr.Audio(label=\"Audio Reply\", type=\"filepath\")\n",
    "    output_image = gr.Image(label=\"Booking Confirmation\")\n",
    "\n",
    "    btn_text.click(fn=book_appointment, inputs=[name_global, time_text], outputs=[output_text, output_audio, output_image])\n",
    "    btn_voice.click(fn=voice_booking, inputs=[voice_input, name_global], outputs=[output_text, output_audio, output_image])\n",
    "\n",
    "    gr.Markdown(\"\"\"---\n",
    "<small>This assistant does **not** give medical advice. It only books appointments within allowed hours.</small>\n",
    "\"\"\")\n",
    "\n",
    "    demo.launch()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f359de0a-28b1-4895-b21d-91d79e494a0d",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
